Méthodologie d'Analyse des Données Quantitatives¶

Introduction :¶

 Dans cette étude on va présenter la méthodologie qu'on a utilisé pour analyser les données quantitatives dans un travail d'analyse exploratoire des données (EDA) sur le jeu de données sur les prix immobiliers de Californie. Dans cette analyse, on a utilisé une approche systématique pour découvrir des informations et des schémas au sein de ce jeu de données. on va vous guider à travers chaque étape, en fournissant des exemples et en illustrant le travail à mesure que nous progressons.

In [ ]:
from sklearn.datasets import fetch_california_housing
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme(style = "darkgrid")
import warnings
warnings.filterwarnings("ignore")
import plotly.io as pio
pio.renderers.default = "notebook+pdf"
In [ ]:
data = fetch_california_housing(as_frame=True)
data = data.frame
sample_data = data.sample(n=900, random_state=42)
data.head()
Out[ ]:
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude MedHouseVal
0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 -122.23 4.526
1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 -122.22 3.585
2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 -122.24 3.521
3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 -122.25 3.413
4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 -122.25 3.422
In [ ]:
sample_data_norm = sample_data.copy(deep=True)
mu = pd.Series({col: 0 for col in sample_data.columns}, dtype="float32")
sigma = pd.Series({col: 0 for col in sample_data.columns}, dtype="float32")

for col in sample_data.columns:
    mu[col] = sample_data[col].mean()
    sigma[col] = sample_data[col].std()
    sample_data_norm[col] = (sample_data[col] - mu[col]) / sigma[col]

Étape 1 : Analyse des Variables Simples¶

In [ ]:
import plotly.express as px
import pandas as pd

ddf = data.copy()
ddf["quantile"] = pd.qcut(data["MedHouseVal"],
                                [0, .25, .5, .75, .9, 1.],
                                labels=False)

fig = px.scatter_mapbox(ddf, 
                        lat="Latitude", 
                        lon="Longitude", 
                        color="quantile",
                        #color_continuous_scale=["fuchsia"],
                        size="MedInc",
                        zoom=5, 
                        height=800,
                        width=1080)

fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
image_bytes = fig.to_image(format='png',  width=1200, height=700, scale=1) 

#instead of using fig.show()
from IPython.display import Image
Image(image_bytes)
Out[ ]:
No description has been provided for this image

 Dans la phase initiale de notre analyse, nous avons effectué une analyse des variables simples. Voici ce que nous avons fait :

1.1 Statistiques Sommaires et STatistiques de Normalité :¶

 Le calcule des statistiques sommaires telles que la moyenne, la médiane, max, min, et l'écart type. en plus, des statistiques de normalité comme Kurtosis, Skewness pour comprendre la distribution.

In [ ]:
from scipy.stats import skew, kurtosis
import pandas_flavor as pf



skimmed_data = data.describe().transpose()


skimmed_data['Skewness'] = data.apply(lambda x: skew(x))
skimmed_data['Kurtosis'] = data.apply(lambda x: kurtosis(x))


from scipy.stats import jarque_bera
skimmed_data['Jarque_Bera'] = data.apply(lambda x: jarque_bera(x)[0])

skimmed_data = skimmed_data.reset_index().rename(columns={'index': 'Variable'})


numeric_cols = skimmed_data.select_dtypes(include=[float]).columns
skimmed_data[numeric_cols] = skimmed_data[numeric_cols].round(3)

skimmed_data
Out[ ]:
Variable count mean std min 25% 50% 75% max Skewness Kurtosis Jarque_Bera
0 MedInc 20640.0 3.871 1.900 0.500 2.563 3.535 4.743 15.000 1.647 4.951 3.040708e+04
1 HouseAge 20640.0 28.639 12.586 1.000 18.000 29.000 37.000 52.000 0.060 -0.801 5.639180e+02
2 AveRooms 20640.0 5.429 2.474 0.846 4.441 5.229 6.052 141.909 20.696 879.140 6.661564e+08
3 AveBedrms 20640.0 1.097 0.474 0.333 1.006 1.049 1.100 34.067 31.315 1636.315 2.306047e+09
4 Population 20640.0 1425.477 1132.462 3.000 787.000 1166.000 1725.000 35682.000 4.935 73.535 4.734157e+06
5 AveOccup 20640.0 3.071 10.386 0.692 2.430 2.818 3.282 1243.333 97.632 10648.430 9.754739e+10
6 Latitude 20640.0 35.632 2.136 32.540 33.930 34.260 37.710 41.950 0.466 -1.118 1.821268e+03
7 Longitude 20640.0 -119.570 2.004 -124.350 -121.800 -118.490 -118.010 -114.310 -0.298 -1.330 1.826564e+03
8 MedHouseVal 20640.0 2.069 1.154 0.150 1.196 1.797 2.647 5.000 0.978 0.328 3.380475e+03

1.2 Boîtes à Moustaches :¶

 Les boîtes à moustaches ont été employées pour mettre en évidence les valeurs aberrantes et les variations importantes dans les prix des logements. Elles offrent une vue synthétique des données, mettant en évidence les quartiles et les données extrêmes et offre une visualisation de la table du sommaire statistique.

In [ ]:
custom_palette = sns.color_palette("flare", 10)

plt.figure(figsize=(10, 7))
sns.boxplot(data=sample_data_norm, palette=custom_palette)

plt.subplots_adjust(hspace=0.7, wspace=0.4)

plt.show()
No description has been provided for this image

1.3 Visualisation des Histogrammes :¶

Visualisation des histogrammes pour représenter graphiquement et comprendre la distribution de chaque variable.

In [ ]:
fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(12, 10))


for i, column in enumerate(sample_data.columns):
    row, col = divmod(i, 3)  
    ax = axes[row, col]      
    sns.distplot(sample_data[column], bins=10, ax=ax, color='blue', kde=True)
    ax.set_title(f'Distribution of {column}')  


plt.subplots_adjust(hspace=0.7, wspace=0.4)


plt.show()
No description has been provided for this image

On a discrétisé en groupes la variable, ce qui nous a permis de regrouper des maisons par tranches d'âge. Ensuite, on a créé un graphique à barres pour illustrer la distribution des maisons dans chaque tranche d'âge.

In [ ]:
bin_edges = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
bin_labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80-89', '90+']

# Create a new column with the age bins
data['age_bins'] = pd.cut(data['HouseAge'], bins=bin_edges, labels=bin_labels)

# Group by the age bins and count the number of houses in each bin
age_grouped = data['age_bins'].value_counts().reset_index()
age_grouped.columns = ['Age Group', 'Count']

# Create a bar plot using Plotly Express
fig = px.bar(age_grouped, x='Age Group', y='Count', title='House Age Distribution')
fig.update_layout(width=800, height=600)

fig.show()

Étape 2 : Analyse Multivariée¶

  Dans la deuxième étape, on a exploré les relations entre différentes variables ie analyse bivariée pour identifier les corrélations et les tendances. Voici ce qu'on a fait :

 2.1 Calcul de la Corrélation :¶

   Le calcul des coefficients de corrélation nous permet de mesurer la force et la direction des relations entre les variables. Une corrélation positive indique une augmentation conjointe, tandis qu'une corrélation négative indique une variation inverse.

In [ ]:
data = data.drop("age_bins",axis = 1)
correlation_matrix = data.corr()

plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap=sns.cubehelix_palette(as_cmap=True))
plt.title("Correlation Matrix Heatmap");
No description has been provided for this image

2.2 Nuages de Points (Scatter Plots) :¶

 Les nuages de points sont des graphiques bidimensionnels qui représentent la relation entre deux variables. Ils nous aident à visualiser les tendances, les schémas et les valeurs atypiques dans les données. L'utilisation du "pair plot" permet d'observer les interactions entre différentes variables en un seul graphique.

In [ ]:
columns_drop = ["Longitude", "Latitude"]
rng = np.random.RandomState(0)
indices = rng.choice(np.arange(data.shape[0]), size=500, replace=False)
subset = data.iloc[indices].drop(columns=columns_drop)
subset["MedHouseVal"] = pd.qcut(subset["MedHouseVal"], 6, retbins=False)
subset["MedHouseVal"] = subset["MedHouseVal"].apply(lambda x: x.mid)
sns.pairplot(data=subset, hue="MedHouseVal", palette="viridis");
No description has been provided for this image

Pretraitement¶

on a appliqué la normalisation aux données d'âge pour mettre toutes les variables sur une échelle comparable.

In [ ]:
df = data.copy(deep=True)
μ = pd.Series({col: 0 for col in data.columns}, dtype="float32")
σ = pd.Series({col: 0 for col in data.columns}, dtype="float32")

for col in data.columns:
    μ[col] = data[col].mean()
    σ[col] = data[col].std()
    df[col] = (data[col] - μ[col]) / σ[col]
df.head()
Out[ ]:
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude MedHouseVal
0 2.344709 0.982119 0.628544 -0.153754 -0.974405 -0.049595 1.052523 -1.327803 2.129580
1 2.332181 -0.607004 0.327033 -0.263329 0.861418 -0.092510 1.043159 -1.322812 1.314124
2 1.782656 1.856137 1.155592 -0.049015 -0.820757 -0.025842 1.038478 -1.332794 1.258663
3 0.932945 1.856137 0.156962 -0.049832 -0.766010 -0.050328 1.038478 -1.337785 1.165072
4 -0.012881 1.856137 0.344702 -0.032905 -0.759828 -0.085614 1.038478 -1.337785 1.172871

Étape 3 : Réduction de Dimension et Visualisation¶

  Dans la dernière phase de notre analyse, on a appliqué l'algorithme t-SNE (t-distributed Stochastic Neighbor Embedding) pour réduire la dimensionnalité de nos données et les visualiser en 2D et 3D. Cette étape était cruciale pour obtenir des informations plus approfondies sur le jeu de données.

  3.1 Algorithme t-SNE :¶

   L'algorithme t-SNE, ou t-distributed Stochastic Neighbor Embedding, est une technique de réduction de dimension. Il utilise une distribution spécifique appelée distribution de Student (t-distribution) pour transformer des données de haute dimension en un espace de dimension inférieure. L'objectif est de préserver les relations entre les points. Pour ce faire, il groupe les points similaires et les éloigne les uns des autres dans l'espace de dimension réduite. La distribution de Student est essentielle car elle permet de former des groupes compacts de points similaires tout en maintenant une séparation adéquate entre les groupes distincts. Cela en fait un outil précieux pour la visualisation de données complexes et la découverte de structures cachées.

et voici une visualisation des résultats en 2D :

In [ ]:
import pandas as pd
import plotly.express as px
from sklearn.manifold import TSNE


tsne = TSNE(n_components=2,
            perplexity=50,
            early_exaggeration=20.0,
            init='pca',
            random_state=10,
            verbose=0)


df["quantile"] = pd.qcut(data["MedHouseVal"],
                                [0, .25, .5, .75, .9, 1.],
                                labels=False)


df_tsne = tsne.fit_transform(df.drop(["MedHouseVal"], axis=1))


df_tsne = pd.DataFrame(data={"col0": df_tsne[:, 0],
                             "col1": df_tsne[:, 1]})
df_tsne["value"] = data["MedHouseVal"]
df_tsne["income"] = data["MedInc"]
df_tsne["quantile"] = df["quantile"]


sample_tsne = df_tsne.sample(frac=0.9)


sample_tsne['quantile'] = sample_tsne['quantile'].astype(str)


fig = px.scatter(sample_tsne, x="col0", y="col1", size="income", color="quantile", text=None)
fig.update_layout(width=800, height=600,title="t-SNE 2D Visualization" ,title_x=0.5)
image_bytes = fig.to_image(format='png',  width=1200, height=700, scale=1) 


Image(image_bytes)
Out[ ]:
No description has been provided for this image

 On peut voir, grâce à la couleur des bulles attribuée par la catégorie forcée, que l'algorithme parvient en quelque sorte à identifier des couches de prix en utilisant uniquement deux variables. Cependant, il est visible qu'il a encore du mal à former des groupes parfaitement distincts pour la valeur des catégories choisies.

3.2 Visualisation en 3D :¶

 Nous avons étendu notre analyse en créant une visualisation en 3D pour obtenir une perspective plus complète sur le jeu de données. Voici un exemple du jeu de données sur les prix immobiliers de Californie dans l'espace tridimensionnel.

In [ ]:
tsne3 = TSNE(n_components=3,
             perplexity=30,
             early_exaggeration=20.0,
             init='pca',
             random_state=10)

df_tsne3 = tsne3.fit_transform(df.drop(["MedHouseVal"], axis=1))
df_tsne3 = pd.DataFrame(data={"col0": df_tsne3[:,0],
                              "col1": df_tsne3[:,1],
                              "col2": df_tsne3[:,2]})
df_tsne3["value"] = data["MedHouseVal"]
df_tsne3["income"] = data["MedInc"]
df_tsne3["quantile"] = df["quantile"]

df_tsne3["quantile"] = df_tsne3["quantile"].astype(str)

sample_tsne3 = df_tsne3.sample(frac=1)

fig = px.scatter_3d(sample_tsne3,
                    x="col0", y="col1", z="col2",
                    color="quantile",
                    text=None)
fig.update_layout(width=800, height=600,title="t-SNE 3D Visualization" ,title_x=0.5)

image_bytes = fig.to_image(format='png',  width=1200, height=700, scale=1) 


from IPython.display import Image
Image(image_bytes)
Out[ ]:
No description has been provided for this image

3.4 PCA¶

In [ ]:
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(df.drop(["MedHouseVal","quantile"],axis=1))

# Explained variance ratio
explained_variance_ratio = pca.explained_variance_ratio_

# Cumulative explained variance
cumulative_variance = np.cumsum(explained_variance_ratio)
# Plot explained variance ratio
plt.figure(figsize=(10, 6))
plt.bar(range(1, len(explained_variance_ratio) + 1), explained_variance_ratio, alpha=0.7, align='center')
plt.xlabel('Principal Component')
plt.ylabel('Explained Variance Ratio')
plt.title('Explained Variance Ratio for Principal Components')
plt.show()

# Plot cumulative explained variance
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(cumulative_variance) + 1), cumulative_variance, marker='o')
plt.xlabel('Number of Principal Components')
plt.ylabel('Cumulative Explained Variance')
plt.title('Cumulative Explained Variance for Principal Components')
plt.grid(True)
plt.show()
No description has been provided for this image
No description has been provided for this image

Conclusion :¶

 En conclusion, cette méthodologie nous a permis d'obtenir des informations précieuses sur le jeu de données sur les prix immobiliers de Californie. En commençant par l'analyse des variables simples, on a compris les caractéristiques de base du jeu de données. L'analyse multivariée nous a aidés à découvrir les relations entre les variables, et la réduction de dimension par l'algorithme t-SNE nous a donné une compréhension plus approfondie de sa structure sous-jacente.